package com.hmall.gateway.filter;

import com.hmall.common.exception.UnauthorizedException;
import com.hmall.common.utils.CollUtils;
import com.hmall.gateway.config.AuthProperties;
import com.hmall.gateway.util.JwtTool;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * 全局认证过滤器
 * 用于网关层的JWT令牌验证和用户身份识别
 * 对需要认证的请求进行拦截和token校验
 */
@Component
@RequiredArgsConstructor
@EnableConfigurationProperties(AuthProperties.class) // 启用认证配置属性
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    private final JwtTool jwtTool;         // JWT工具类，用于token解析
    private final AuthProperties authProperties; // 认证配置属性，获取免认证路径
    private final AntPathMatcher antPathMatcher = new AntPathMatcher(); // Ant路径匹配器

    /**
     * 过滤器核心方法
     * 执行认证逻辑，决定请求是否放行
     * @param exchange 服务器Web交换对象
     * @param chain 网关过滤器链
     * @return Mono<Void> 处理结果
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        // 1. 获取当前请求对象
        ServerHttpRequest request = exchange.getRequest();

        // 2. 判断请求路径是否属于免认证路径
        if (isExclude(request.getPath().toString())) {
            // 无需认证，直接放行请求
            return chain.filter(exchange);
        }

        // 3. 从请求头中获取JWT令牌
        String token = null;
        List<String> headers = request.getHeaders().get("authorization");
        if (!CollUtils.isEmpty(headers)) {
            token = headers.get(0); // 取出第一个授权头
        }

        // 4. 校验并解析JWT令牌
        Long userId = null;
        try {
            userId = jwtTool.parseToken(token); // 解析token获取用户ID
        } catch (UnauthorizedException e) {
            // 令牌无效或已过期，返回401未认证状态
            ServerHttpResponse response = exchange.getResponse();
            response.setRawStatusCode(401); // 设置HTTP状态码为401
            return response.setComplete(); // 结束响应处理
        }

        // 5. 令牌有效时，将用户信息添加到请求头中（供下游服务使用）
        String userInfo = userId.toString();
        ServerWebExchange ex = exchange.mutate()
                .request(b -> b.header("user-info", userInfo)) // 添加user-info请求头
                .build();

        // 6. 将处理后的请求传递给下一个过滤器
        return chain.filter(ex);

    }

    /**
     * 判断请求路径是否属于免认证路径
     * @param antPath 请求路径
     * @return boolean 是否免认证
     */
    private boolean isExclude(String antPath) {

        // 遍历免认证路径配置
        for (String pathPattern : authProperties.getExcludePaths()) {
            if (antPathMatcher.match(pathPattern, antPath)) {
                // 路径匹配成功，属于免认证路径
                return true;
            }
        }
        return false;
    }

    /**
     * 获取过滤器执行顺序
     * 数值越小，优先级越高
     * @return int 顺序值
     */
    @Override
    public int getOrder() {
        return 0;
    }
}